-module(hbq).
-author("iamapo").
-import(werkzeug, [get_config_value/2, logging/2, to_String/1, timeMilliSecond/0]).

%% API
-export([dropmessage/4, createNew/0]).

createNew() ->
  [].

% Fügt Message zur HBQ und versucht sie zur DLQ zu schieben
%
% check ob HBQ über dem limmit kommen würde
% wenn ja wird fehler meldung für fehlende nachrichten erzeugt und verschoben
% wenn nicht wird versucht zu verschieben
dropmessage(Message, Number, HBQ, DLQ) ->
  {ok, ConfigListe} = file:consult("server.cfg"),
  {ok, DeliveryQueueMaxSize} = get_config_value(dlqlimit, ConfigListe),

  werkzeug:logging("NServer.log", lists:concat(["QVerwaltung1>>>: Nachricht ["])),

  if length(HBQ) + 1 >= DeliveryQueueMaxSize / 2 ->
    NewHBQ = [{Number, Message} | HBQ],
    generateFailureMessageAndMove(NewHBQ, DLQ);
  true ->
    NewHBQ = [{Number, Message} | HBQ],
    tryToMoveToDLQ(NewHBQ, DLQ)
  end
.

%wenn HBQ leer return leer
%
%wenn nummern der dlq und hbq zusammen passen wird das tupel verschoben
%und es wird versucht weitere tupel zu verschieben
tryToMoveToDLQ(HBQ, DLQ) ->
  if length(HBQ) > 0 ->
    MinHBQ = getMinNumber(HBQ),
    MaxDLQ = dlq:getMaxNumber(DLQ),
    if MaxDLQ + 1 == MinHBQ ->
      werkzeug:logging("NServer.log", lists:concat([to_String(MinHBQ), ","])),
      {Key, Value} = getTupel(MinHBQ, HBQ),
      NewHBQ = proplists:delete(Key, HBQ),
      NewDLQ = dlq:add(Value, Key, DLQ),
      tryToMoveToDLQ(NewHBQ, NewDLQ);
      true ->
        [HBQ, DLQ]
    end;
    true ->
      [HBQ, DLQ]
  end
.

%generiert fehler nachricht für fehlende nachrichten
%und schreibt soviele Nachrichten wie möglich in die DLQ
generateFailureMessageAndMove(HBQ, DLQ) ->
  MinHBQ = getMinNumber(HBQ),
  MaxDLQ = dlq:getMaxNumber(DLQ),

  %unterscheidung beim logging zwischen einer fehlenden nachricht oder mehreren
  if MaxDLQ + 1 == MinHBQ ->
    werkzeug:logging("NServer.log", lists:concat(["*********Fehlernachricht fuer Nachricht ", to_String(MaxDLQ + 1),
                     " generiert um ", timeMilliSecond()])),
    FailMessage = lists:concat(["FehlerNachricht fuer Nachricht ", to_String(MaxDLQ + 1),
                     " generiert um ", timeMilliSecond()]);
  true ->
    werkzeug:logging("NServer.log", lists:concat(["*********Fehlernachricht fuer Nachrichten ", to_String(MaxDLQ + 1),
                     " bis ", to_String(MinHBQ - 1), " generiert um ", timeMilliSecond()])),
    FailMessage = lists:concat(["FehlerNachricht fuer Nachrichten ", to_String(MaxDLQ + 1),
                     " bis ", to_String(MinHBQ - 1), " generiert um ", timeMilliSecond()])
  end,

  NewDLQ = dlq:add(FailMessage, MinHBQ - 1, DLQ),
  tryToMoveToDLQ(HBQ, NewDLQ)
.

% Gibt tuppel für die Nummer aus
getTupel(Nummer, HBQ) -> lists:keyfind(Nummer, 1, HBQ).

%gibt kleinste nummer in hbq wieder
% wenn hbq leer retun 0
getMinNumber([]) -> 0;
getMinNumber(HoldbackQueue) -> lists:min(proplists:get_keys(HoldbackQueue)).
